from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import DeviceType, Device, DeviceState, DeviceStateHistory
from apps.user.models import UserProfile, User, Family

# 调试用，请无视
# user = User.objects.create_user(username='alice', password='pwd')
# profile = UserProfile.objects.create(user=user)
# family = Family.objects.create(name='MyHome', manager=profile)
class DeviceAPITestCase(APITestCase):
    def setUp(self):
        # 1) 先创建一个 Django User + Profile
        self.user = User.objects.create_user(username='alice', password='pwd')
        self.profile = UserProfile.objects.create(user=self.user)
        # 2) 再用这个 Profile 作为 Family 的 manager
        self.family = Family.objects.create(name='MyHome', manager=self.profile)
        # 3) 最后创建一个 DeviceType
        self.dev_type = DeviceType.objects.create(
            name='TestType',
            capabilities={'switch': True}
        )

    def test_create_device(self):
        """
        POST /devices
        - 返回 201
        - data.name == 'Bed'
        - data.type_id == self.dev_type.id
        - data.family_id == self.family.id
        """
        url = reverse('device-list')
        payload = {
            'name': 'Bed',
            'type_id': self.dev_type.id,
            'family_id': str(self.family.id),    # UUID 需要传字符串?
            'meta': {'location': 'room'}
        }
        resp = self.client.post(url, payload, format='json')
        data = resp.data.get('data', {})
        self.assertEqual(data.get('name'), 'Bed')
        self.assertEqual(data.get('type'), self.dev_type.name)
        self.assertEqual(data.get('family'), str(self.family.name))
        self.assertEqual(resp.status_code, status.HTTP_201_CREATED)

    def test_list_devices(self):
        """
        GET /devices
        - 返回 200
        - data.devices 列表长度 >= 1
        - 每项含 id, name, type_id, family_id, meta, state
        """
        Device.objects.create(
            name='Bed',
            type=self.dev_type,
            family=self.family,
            meta={'location': 'room'}
        )
        url = reverse('device-list')
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertIn('devices', resp.data['data'])
        self.assertGreaterEqual(len(resp.data['data']['devices']), 1)
        wrapper = resp.data.get('data', {})
        devices = wrapper.get('devices', [])
        item = devices[0]
        for field in ('id', 'name', 'type', 'family', 'meta', 'state'):
            self.assertIn(field, item)

    def test_update_state(self):
        """
        PATCH /devices/{id}/state
        - 返回 204
        - DeviceState.state_json 更新
        - DeviceStateHistory 生成记录
        """
        device = Device.objects.create(
            name='Bed',
            type=self.dev_type,
            family=self.family,
            meta={'location': 'room'}
        )
        url = reverse('device-update-state', args=[device.id])
        resp = self.client.patch(url, {'state': {'switch': True}}, format='json')
        self.assertEqual(resp.status_code, status.HTTP_204_NO_CONTENT)

        state = DeviceState.objects.get(device=device)
        self.assertTrue(state.state_json.get('switch'))

        history_qs = DeviceStateHistory.objects.filter(device=device)
        self.assertTrue(history_qs.exists())

    def test_state_history(self):
        """
        GET /devices/{id}/state-history
        - 返回 200
        - data 是列表
        """
        device = Device.objects.create(
            name='Bed',
            type=self.dev_type,
            family=self.family,
            meta={'location': 'room'}
        )
        DeviceStateHistory.objects.create(
            device=device,
            state_json={'is_on': False}
        )
        url = reverse('device-state-history', args=[device.id])
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, status.HTTP_200_OK)
        self.assertTrue(isinstance(resp.data['data'], list))
        self.assertGreaterEqual(len(resp.data['data']), 1)
